package com.gelpag.filter;

import com.alibaba.fastjson.JSON;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import entity.Const;
import entity.Result;
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import tools.utils.Common;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

//把过滤器放到容器中
@Component
public class AuthorityFilter extends ZuulFilter {

    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public String filterType() {
        /**
         * pre 之前执行
         * post之后执行
         */
        return "pre";
    }

    @Override
    public int filterOrder() {
        /**
         * 执行顺序，0表示最优先执行
         */
        return 0;
    }

    /**
     * 当前过滤器是否开启，true表示开启、false表示关闭
     *
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * return 任何的值都可以继续执行,返回null，也可以继续执行
     * 不想要执行需要requestContext.setSendZuulResponse(false)
     *
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        logger.debug("网关过滤器AuthorityFilter-start");
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String url = request.getRequestURI();
        int i = url.indexOf("?");
        if (i > 0) {
            //如果url中包含?,截取掉?以后的内容
            url = url.substring(0, i);
        }
        String token = request.getHeader("token");
        logger.error("==================================token:"+token);
        logger.error("==================================Access-Control-Allow-Origin:"+request.getHeader("Access-Control-Allow-Origin"));
        String new_token = "";

        if (!isNoCheckUrl(url)) {
            //需要验证权限，在token中查询角色对应的权限url，验证不通过直接返回没有权限
            if (Common.isNullString(token)) {
                setResponseBody(requestContext, new Result(Const.RESULT_1,"token is null!","",""));
                return null;
            }
            if (!token.startsWith(Const.PRE_TOKEN)) {
                //token 不是以gelpag_ 开头的，非法
                setResponseBody(requestContext, new Result(Const.RESULT_1,"token is error!","",""));
                return null;
            }

            try {
                Claims claims = Jwts.parser().setSigningKey(Const.JWT_KEY).parseClaimsJws(token.replace(Const.PRE_TOKEN,"")).getBody();
                //在token中获得角色列表
                List<String> roleList = (ArrayList<String>)claims.get("roles");
                int pass = 0;
                for(String role_id: roleList) {
                    //根据role_id获得对应的权限，判断权限url和requestUrl是否匹配
                    String role_url_str=stringRedisTemplate.opsForValue().get(Const.REDIS_HEAD_BASE + "_" + Const.REDIS_CHECK_URL + "_" + role_id);
                    //获得角色拥有的所有url
                    List<String> role_url = (List<String>)JSON.parse(role_url_str);
                    if(role_url != null){
                        if(role_url.contains(url)){
                            //验证通过,拥有url权限
                            pass = 1;
                            break;
                        }
                    }
                }
                if (pass == 0) {
                    //验证没通过，设置拦截器返回
                    setResponseBody(requestContext, new Result(Const.RESULT_2,url+"===no permission", token, ""));
                } else {
                    //验证通过 刷新token
                    new_token = refreshToken(token);
                    this.setHeader(requestContext,new_token);

                }
            } catch (Exception e) {
                e.printStackTrace();
                //token过期，拦截
                setResponseBody(requestContext, new Result(Const.RESULT_F1,"登录超时！", token, ""));
            }
        } else {
            //不需要验证权限
            if (!Common.isNullString(token)) {
                if (!token.startsWith(Const.PRE_TOKEN)) {
                    //token 不是以“gelpag_”开头，非法
                    setResponseBody(requestContext,new Result(Const.RESULT_1,"token is error!",token,""));
                    return null;
                }
                //如果token不为空，将token刷新后，传递
                new_token = refreshToken(token);
                this.setHeader(requestContext,new_token);
            }
        }
        return null;
    }

    /**
     * 刷新token
     * @param token
     * @return
     */
    private String refreshToken(String token) {

        try {
            //如果没有token，就返回无
            if(Common.isNullString(token)) {
                return "";
            }

            token = token.replace(Const.PRE_TOKEN, "");
            Claims claims = Jwts.parser().setSigningKey(Const.JWT_KEY).parseClaimsJws(token).getBody();
            HashMap<String, Object> userMap = new HashMap<String, Object>();
            userMap.put("user_id", (String)claims.get("user_id"));
            userMap.put("user_name", (String)claims.get("user_name"));
            userMap.put("user_type", (String) claims.get("user_type"));
            userMap.put("roles", (List<String>) claims.get("roles"));
            userMap.put("unit_ids", (List<String>) claims.get("unit_ids"));
            userMap.put("unit_id", (String) claims.get("unit_id"));

            return Common.generateToken(userMap);
        } catch (Exception e) {
            e.printStackTrace();
            //如果token过期，直接返回原来的token
            return token;
        }
    }

    /**
     * url是否需要权限验证
     * @param url
     * @return
     */
    private boolean isNoCheckUrl(String url){

        //获取redis中数据（为字串类型）
        String redisNoCheckUrl_str=stringRedisTemplate.opsForValue().get(Const.REDIS_HEAD_BASE+"_"+Const.REDIS_NO_CHECK_URL);
        //将String类型转换为List集合形式
        List<String> redisNoCheckUrl=(List<String>)JSON.parse(redisNoCheckUrl_str);
        //如果完全一致认为通过（为空证明所有的url都需要验证权限）
        if(redisNoCheckUrl == null)return false;
        return redisNoCheckUrl.contains(url);
    }

    private void setResponseBody(RequestContext requestContext, Result result) {
        requestContext.setResponseBody(JSON.toJSONString(result));
        requestContext.getResponse().setContentType("application/json;charset=UTF-8");
        //验证没通过，设置拦截器返回
        requestContext.setSendZuulResponse(false);
    }

    private void setHeader(RequestContext requestContext, String new_token) {
        requestContext.addZuulRequestHeader("token", new_token);
    }
}
